"""
混入类
"""

import json

from django.db.models import Model

from my_typing import *


class ToDictMixin:
    """ 转换成字典 Mixin """

    BASE_FIELDS: TupleStr = (
        "id",
        "is_deleted",
        "create_time",
        "update_time",
        "is_show",
        "is_secret",
        "password",
    )

    def to_dict(
        self: Model,
        shows: TupleStr = (),
        no_shows: TupleStr = (),
        hide_base_fields: bool = True,
    ) -> dict:
        """
        转换成字典

        Args:
            shows: 展示的字段
            no_shows: 不展示的字段
            hide_base_fields: 是否隐藏基础字段，默认为 True

        Returns:
            转换后的字典
        """

        from utils.converter_utils.time import TimeConverter
        from utils.django_utils import JsonEncoder

        model_fields: TupleStr = tuple(
            _field.name
            for _field in self._meta.fields  # noqa
        )

        attr_dict: dict = {
            _field: getattr(self, _field)
            for _field in model_fields
        }

        if (
            shows
            and no_shows
        ):
            raise ValueError("shows 与 no_shows 不允许同时赋值")

        if shows_missing_fields := set(shows) - set(model_fields):
            raise AttributeError(f"当前对象没有 <{'、'.join(shows_missing_fields)}> 属性")

        if no_shows_missing_fields := set(no_shows) - set(model_fields):
            raise AttributeError(f"当前对象没有 <{'、'.join(no_shows_missing_fields)}> 属性")

        remove_fields: SetStr = set()

        # 移除基础字段
        if hide_base_fields:
            remove_fields.update(ToDictMixin.BASE_FIELDS)

        if shows:
            remove_fields.update(set(model_fields) - set(shows))

        elif no_shows:
            remove_fields.update(set(no_shows))

        for _field in remove_fields:
            attr_dict.pop(_field, None)

        for _field in attr_dict.copy():
            value = attr_dict[_field]
            need_pop: bool = False

            # 处理时间字段
            if isinstance(value, (datetime, date, time)):
                attr_dict[_field] = TimeConverter.auto_2_str(value)

            # 特殊处理外键字段
            elif isinstance(value, Model):
                attr_dict[f"{_field}_id"] = value.pk
                # 外键字段，暂不解析关联数据属性
                # attr_dict[_field] = ToDictMixin.to_dict(value)
                need_pop = True

            else:
                # JSON 序列化
                try:
                    json.dumps({_field: value}, cls=JsonEncoder)

                except:  # noqa
                    need_pop = True

            if need_pop:
                attr_dict.pop(_field, None)

        return attr_dict
